﻿String.prototype.hashCode = function(){
//	return this;
/**/
	var hash = 0;
	if (this.length === 0) return 0;//code;
	for (var i = 0; i < this.length; i++) {
		hash = 31*hash+this.charCodeAt(i);
		hash = hash & hash; // Convert to 32bit integer
	}
	return hash;
/**/
};

if (!log) var log = function(){}

var JSGantt;
if (!JSGantt) JSGantt = {};

var vTimeout = 0;
var vBenchTime = new Date().getTime();

var TaskPid = 1;

const MINUTE = 60 * 1000;
const HOUR = 60 * MINUTE;
const DAY = 24 * HOUR;

var bgoverColor = "#ffffdd";
var bgtaskColor = "#ffffff";
var bggroupColor = "#f3f3f3";
var bgtodayColor = "#e3e3ff";
var bgweekendColor = "#eaeaea";

var STATUSES = ['new','WorkerAppointed','reopened','inwork','fixed','readyfortest','TesterAppointed','intest','accepted','closed','rejected'];
var STATUS = {
	opened:{name: 'Новые',stats:['new','WorkerAppointed','reopened','inwork']},
	fixed:{name: 'Исправлены',stats:['fixed','readyfortest']},
	test:{name: 'Тестируются',stats:['TesterAppointed','intest']},
	closed:{name: 'Закрытые',stats:['accepted','closed','rejected']}};
var STATS = {};//{'new':1,'WorkerAppointed':1,'reopened':1,'inwork':1,'fixed':1,'readyfortest':1,'TesterAppointed':1,'intest':1,'accepted':1,'closed':1,'rejected':1};


/**
 * Creates a task (one row) in gantt object
 * @class TaskItem
 * @namespace JSGantt
 * @constructor
 * @for JSGantt

 * @param pID {Number} Task unique numeric ID
 * @param pName {String} Task Name
 * @param pStart {Date} Task start date/time (not required for pGroup=1 )
 * @param pEnd {Date} Task end date/time, you can set the end time to 12:00 to indicate half-day (not required for pGroup=1 )
 * @param pColor {String} Task bar RGB value
 * @param pLink {String} Task URL, clicking on the task will redirect to this url. Leave empty if you do not with the Task also serve as a link
 * @param pMile {Boolean} Determines whether task is a milestone (1=Yes,0=No)
 * @param pRes {String} Resource to perform the task
 * @param pComp {Number} Percent complete (Number between 0 and 100)
 * @param pGroup {Boolean}
 * @param pParent {Number} ID of the parent task
 * @param pOpen {Boolean}
 * @param pDepend {String} Comma seperated list of IDs this task depends on
 * @param pCaption {String} Caption to be used instead of default caption (Resource).
 * note : you should use setCaption("Caption") in order to display the caption
 * @return void
 */
//JSGantt.TaskItem = function(pName, pStart, pEnd, pLoad, pColor, pDates, pLink, pMile, pRes, pComp, pGroup, pParent, pOpen, pDepend, pCaption) {
//var isGroup = task.subtask != undefined && task.subtask.length > 0;
// Parameters             	 (pName,     pStart,     pEnd,     pLoad,     pColor,                      pDates,	   pLink, 	    pMile, 	pRes,pComp, pGroup, 	pParent,pOpen, pDepend, pCaption)
//var ti = new JSGantt.TaskItem(task.name, task.start, task.end, task.load, JSGantt.getColor(task.load), task.dates, task.link, 	0, 		'',  0, 	isGroup?1:0,parent, 0);
JSGantt.TaskItem = function(task, pParent, pOpen, pMile, pRes, pComp, pDepend, pCaption) {

	var vID = TaskPid++;
    this.getID = function() {return vID};

	var vName = task.name;
    this.getName = function() {return vName};

	var vDates = task.dates;
    this.getDates = function() {return vDates};

	var vStart = new Date();
    this.getStart = function() {return vStart};
    this.setStart = function(pStart) {vStart = pStart;};

	var vEnd = new Date();
    this.getEnd = function() {return vEnd};
    this.setEnd = function(pEnd) {vEnd = pEnd;};

	var vColor = JSGantt.getColorByStatus(task.status);
    this.getColor = function() {return vColor};

	var trac_name = task.trac;
	if (g.getDatatype() == 2) {
		var ti = g.getTaskItemByID(pParent);
		if (ti) trac_name = ti.getName();
	}
	var vLink = (trac_name && task.id) ? "http://td/trac/"+trac_name+"/ticket/"+task.id : undefined;//task.link;
    this.getLink = function() {return vLink};

	var vMile = pMile;
    this.getMile = function() {return vMile};

	var vRes = pRes;
    this.getResource = function() {if (vRes) return vRes; else return '&nbsp';};

	var vComp = pComp;
    this.getCompVal = function() {if (vComp) return vComp; else return 0;};
    this.setCompVal = function(pCompVal) {vComp = pCompVal;};
    this.getCompStr = function() {if (vComp) return vComp + '%'; else return '';};

	var vGroup = task.subtask != undefined && task.subtask.length > 0;
    this.getGroup = function() {return vGroup};

	var vParent = pParent;
    this.getParent = function() {return vParent};

	var vOpen = pOpen;
    this.getOpen = function() {return vOpen};
    this.setOpen = function(pOpen) {vOpen = pOpen;};

	var vDepend = pDepend;
    this.getDepend = function() {if (vDepend) return vDepend; else return null; };
    this.setDepend = function(pDepend) {vDepend = pDepend;};

	var vCaption = task.status ? task.status : '';//pCaption;
    this.getCaption = function() {
		if (vStart > vEnd)
			return vCaption + ' (Bad dates)';
		else return vCaption;
	};

	var vDuration = 0;
    this.getDuration = function(vFormat) {
        var tmpPer;
        if (vMile)
            vDuration = '-';
        else if (vFormat == 'hour') {
            tmpPer = Math.ceil((this.getEnd() - this.getStart()) / HOUR);
            vDuration = tmpPer == 1 ? '1 Hour' : tmpPer + ' Hours';
        }
        else if (vFormat == 'minute') {
            tmpPer = Math.ceil((this.getEnd() - this.getStart()) / MINUTE);
            vDuration = tmpPer == 1 ? '1 Minute' : tmpPer + ' Minutes';
        }
        else { //if(vFormat == 'day') {
            tmpPer = Math.ceil((this.getEnd() - this.getStart()) / DAY + 1);
            vDuration = tmpPer == 1 ? '1 Day' : tmpPer + ' Days';
        }

        //else if(vFormat == 'week') {
        //   tmpPer =  ((this.getEnd() - this.getStart()) /  DAY + 1)/7;
        //   if(tmpPer == 1)  vDuration = '1 Week';
        //   else             vDuration = tmpPer + ' Weeks';
        //}

        //else if(vFormat == 'month') {
        //   tmpPer =  ((this.getEnd() - this.getStart()) /  DAY + 1)/30;
        //   if(tmpPer == 1) vDuration = '1 Month';
        //   else            vDuration = tmpPer + ' Months';
        //}

        //else if(vFormat == 'quater') {
        //   tmpPer =  ((this.getEnd() - this.getStart()) /  DAY + 1)/120;
        //   if(tmpPer == 1) vDuration = '1 Qtr';
        //   else            vDuration = tmpPer + ' Qtrs';
        //}
        return( vDuration )
    };

	var vLevel = 0;
    this.getLevel = function() {return vLevel};
    this.setLevel = function(pLevel) {vLevel = pLevel;};

	var vNumKid = 0;
    this.getNumKids = function() {return vNumKid};
    this.setNumKid = function(pNumKid) {vNumKid = pNumKid;};

	var vVisible = false;
    this.getVisible = function() {return vVisible};
    this.setVisible = function(pVisible) {vVisible = pVisible;};

	var x1, y1, x2, y2;
    this.getStartX = function() {return x1};
    this.setStartX = function(pX) {x1 = pX;};
    this.getStartY = function() {return y1};
    this.setStartY = function(pY) {y1 = pY;};
    this.getEndX = function() {return x2};
    this.setEndX = function(pX) {x2 = pX;};
    this.getEndY = function() {return y2};
    this.setEndY = function(pY) {y2 = pY;};

    var vLoad = task.load;
    this.getLoad = function() {return vLoad;};
    this.setLoad = function(pLoad) {vLoad = pLoad;};

    var vOffset = 0;
    this.getOffset = function() {return vOffset;};
    this.setOffset = function(pOffset) {vOffset = pOffset;};

    var vTrac = task.trac;
    this.getTrac = function() {return vTrac;};
	this.getTrueTrac = function() {
		var trac_name = vTrac;
		if (g.getDatatype() == 2) {
			var ti = g.getTaskItemByID(vParent);
			if (ti) trac_name = ti.getName();
		}
		return trac_name;
	};

    var vTicket = task.id;
    this.getTicket = function() {return vTicket;};

    var vStatus = task.status;
    this.getStatus = function() {return vStatus;};

	var vPriority = task.priority;
	this.getPriority = function() {return vPriority;};

	if (true || vGroup != 1) {
		vStart = JSGantt.parseDateStr(task.start, g.getDateInputFormat());
		vEnd = JSGantt.parseDateStr(task.end, g.getDateInputFormat());
		//TODO: support dates
	}
};


/**
 * Creates the gant chart. for example:

 <p>var g = new JSGantt.GanttChart('g',document.getElementById('GanttChartDIV'), 'day');</p>

 var g = new JSGantt.GanttChart( - assign the gantt chart to a javascript variable called 'g'
 'g' - the name of the variable that was just assigned (will be used later so that gantt object can reference itself)
 document.getElementById('GanttChartDIV') - reference to the DIV that will hold the gantt chart
 'day' - default format will be by day

 *
 * @class GanttChart
 * @param pGanttVar {String} the name of the gantt chart variable
 * @param pDiv {String} reference to the DIV that will hold the gantt chart
 * @param pFormat {String} default format (minute,hour,day,week,month,quarter)
 * @return void
 */

JSGantt.GanttChart = function(pGanttVar, pDiv, pFormat) {
	/**
	 * The name of the gantt chart variable
	 * @property vGanttVar
	 * @type String
	 * @default pGanttVar
	 * @private
	 */
	var vGanttVar = pGanttVar;
	/**
	 * The name of the gantt chart DIV
	 * @property vDiv
	 * @type String
	 * @default pDiv
	 * @private
	 */
	var vDiv = pDiv;
	/**
	 * Selected format (minute,hour,day,week,month)
	 * @property vFormat
	 * @type String
	 * @default pFormat
	 * @private
	 */
	var vFormat = pFormat;
	/**
	 * Show resource column
	 * @property vShowRes
	 * @type Number
	 * @default 1
	 * @private
	 */
	var vShowRes = 1;
	/**
	 * Show duration column
	 * @property vShowDur
	 * @type Number
	 * @default 1
	 * @private
	 */
	var vShowDur = 1;
	/**
	 * Show percent complete column
	 * @property vShowComp
	 * @type Number
	 * @default 1
	 * @private
	 */
	var vShowComp = 1;
	/**
	 * Show start date column
	 * @property vShowStartDate
	 * @type Number
	 * @default 1
	 * @private
	 */
	var vShowStartDate = 1;
	/**
	 * Show end date column
	 * @property vShowEndDate
	 * @type Number
	 * @default 1
	 * @private
	 */
	var vShowEndDate = 1;
	/**
	 * Date input format
	 * @property vDateInputFormat
	 * @type String
	 * @default "mm/dd/yyyy"
	 * @private
	 */
	var vDateInputFormat = "mm/dd/yyyy";
	/**
	 * Date display format
	 * @property vDateDisplayFormat
	 * @type String
	 * @default "mm/dd/yy"
	 * @private
	 */
	var vDateDisplayFormat = "mm/dd/yy";
	var vShowDep = 1;
	var vDatatype = 1;

	var vNumUnits = 0;
	var vCaptionType;
	var vDepId = 1;
	var vTaskList = new Array();
	var vFormatArr = new Array("day", "week", "month", "quarter");
	var vQuarterArr = new Array(1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4);
	var vMonthDaysArr = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
	var vMonthArr = new Array("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December");
	var chartStart;
	var chartEnd;
	var widthLeft = 300;
	var widthRight =800;

	/**
	 * Set current display format (minute/hour/day/week/month/quarter)
	 * Only the first 4 arguments are used, for example:
	 * <code>
	 * g.setFormatArr("day","week","month");
	 * </code>
	 * will show 3 formatting options (day/week/month) at the bottom right of the gantt chart
	 * @method setFormatArr
	 * @return {void}
	 */
	this.setFormatArr = function() {
		vFormatArr = new Array();
		for (var i = 0; i < arguments.length; i++) {
			vFormatArr[i] = arguments[i];
		}
		if (vFormatArr.length > 4) {
			vFormatArr.length = 4;
		}
	};
	/**
	 * Show/Hide resource column
	 * @param pShow {Number} 1=Show,0=Hide
	 * @method setShowRes
	 * @return {void}
	 */
	this.setShowRes = function(pShow) {vShowRes = pShow;};
	/**
	 * Show/Hide duration column
	 * @param pShow {Number} 1=Show,0=Hide
	 * @method setShowDur
	 * @return {void}
	 */
	this.setShowDur = function(pShow) {vShowDur = pShow;};
	this.setShowDep = function(pShow) {vShowDep = pShow;};
	/**
	 * Show/Hide completed column
	 * @param pShow {Number} 1=Show,0=Hide
	 * @method setShowComp
	 * @return {void}
	 */
	this.setShowComp = function(pShow) {vShowComp = pShow;};
	/**
	 * Show/Hide start date column
	 * @param pShow {Number} 1=Show,0=Hide
	 * @method setShowStartDate
	 * @return {void}
	 */
	this.setShowStartDate = function(pShow) {vShowStartDate = pShow;};
	/**
	 * Show/Hide end date column
	 * @param pShow {Number} 1=Show,0=Hide
	 * @method setShowEndDate
	 * @return {void}
	 */
	this.setShowEndDate = function(pShow) {vShowEndDate = pShow;};
	/**
	 * Overall date input format
	 * @param pShow {String} (mm/dd/yyyy,dd/mm/yyyy,yyyy-mm-dd)
	 * @method setDateInputFormat
	 * @return {void}
	 */
	this.setDateInputFormat = function(pShow) {vDateInputFormat = pShow;};
	/**
	 * Overall date display format
	 * @param pShow {String} (mm/dd/yyyy,dd/mm/yyyy,yyyy-mm-dd)
	 * @method setDateDisplayFormat
	 * @return {void}
	 */
	this.setDateDisplayFormat = function(pShow) {vDateDisplayFormat = pShow;};
	/**
	 * Set gantt caption
	 * @param pType {String}
	 <p>Caption-Displays a custom caption set in TaskItem<br>
	 Resource-Displays task resource<br>
	 Duration-Displays task duration<br>
	 Complete-Displays task percent complete</p>
	 * @method setCaptionType
	 * @return {void}
	 */
	this.setCaptionType = function(pType) {vCaptionType = pType};
	/**
	 * Set current display format and redraw gantt chart (minute/hour/day/week/month/quarter)
	 * @param pFormat {String} (mm/dd/yyyy,dd/mm/yyyy,yyyy-mm-dd)
	 * @method setFormat
	 * @return {void}
	 */
	this.setFormat = function(pFormat) {
		vFormat = pFormat;
		this.Draw();
	};
	this.setColWidth = function(w1, w2) {
		widthLeft = w1;
		widthRight = w2;
	};
	this.setDatatype = function(pDatatype) {
		vDatatype = pDatatype;
	};
	this.getDatatype = function() {
		return vDatatype;
	};


	/**
	 * Returns whether resource column is shown
	 * @method getShowRes
	 * @return {Number}
	 */
	this.getShowRes = function() {return vShowRes};
	/**
	 * Returns whether duration column is shown
	 * @method getShowDur
	 * @return {Number}
	 */
	this.getShowDur = function() {return vShowDur};
	/**
	 * Returns whether percent complete column is shown
	 * @method getShowComp
	 * @return {Number}
	 */
	this.getShowComp = function() {return vShowComp};
	/**
	 * Returns whether start date column is shown
	 * @method getShowStartDate
	 * @return {Number}
	 */
	this.getShowStartDate = function() {return vShowStartDate};
	/**
	 * Returns whether end date column is shown
	 * @method getShowEndDate
	 * @return {Number}
	 */
	this.getShowEndDate = function() {return vShowEndDate};
	/**
	 * Returns date input format
	 * @method getDateInputFormat
	 * @return {String}
	 */
	this.getDateInputFormat = function() {return vDateInputFormat};
	/**
	 * Returns current display format
	 * @method getDateDisplayFormat
	 * @return {String}
	 */
	this.getDateDisplayFormat = function() {return vDateDisplayFormat};
	/**
	 * Returns current gantt caption type
	 * @method getCaptionType
	 * @return {String}
	 */
	this.getCaptionType = function() {return vCaptionType};
	/**
	 * Calculates X/Y coordinates of a task and sets the Start and End properties of the TaskItem
	 * @method CalcTaskXY
	 * @return {void}
	 */
	this.CalcTaskXY = function () {
		var vList = this.getList();
		var vTaskDiv;
		var vParDiv;
		var vLeft, vTop, vHeight, vWidth;

		for (var i = 0; i < vList.length; i++) {
			vID = vList[i].getID();
			vTaskDiv = document.getElementById("taskbar_" + vID);
			vBarDiv = document.getElementById("bardiv_" + vID);
			vParDiv = document.getElementById("childgrid_" + vID);

			if (vBarDiv) {
				vList[i].setStartX(vBarDiv.offsetLeft);
				vList[i].setStartY(vParDiv.offsetTop + vBarDiv.offsetTop + 6);
				vList[i].setEndX(vBarDiv.offsetLeft + vBarDiv.offsetWidth);
				vList[i].setEndY(vParDiv.offsetTop + vBarDiv.offsetTop + 6);
			}

		}
		;
	};

	/**
	 * Adds a TaskItem to the Gantt object task list array
	 * @method AddTaskItem
	 * @return {void}
	 */
	this.AddTaskItem = function(value) {vTaskList.push(value);};
	/**
	 * Returns task list Array
	 * @method getList
	 * @return {Array}
	 */
	this.getList = function() {return vTaskList};

	/**
	 * Clears dependency lines between tasks
	 * @method clearDependencies
	 * @return {void}
	 */
	this.clearDependencies = function() {
		var parent = document.getElementById('rightside');
		var depLine;
		var vMaxId = vDepId;
		for (var i = 1; i < vMaxId; i++) {
			depLine = document.getElementById("line" + i);
			if (depLine) {
				parent.removeChild(depLine);
			}
		}

		vDepId = 1;
	};
	/**
	 * Draw a straight line (colored one-pixel wide DIV), need to parameterize doc item
	 * @method sLine
	 * @return {void}
	 */
	this.sLine = function(x1, y1, x2, y2) {

		vLeft = Math.min(x1, x2);
		vTop = Math.min(y1, y2);
		vWid = Math.abs(x2 - x1) + 1;
		vHgt = Math.abs(y2 - y1) + 1;

		vDoc = document.getElementById('rightside');

		// retrieve DIV
		var oDiv = document.createElement('div');

		oDiv.id = "line" + vDepId++;
		oDiv.style.position = "absolute";
		oDiv.style.margin = "0px";
		oDiv.style.padding = "0px";
		oDiv.style.overflow = "hidden";
		oDiv.style.border = "0px";

		// set attributes
		oDiv.style.zIndex = 0;
		oDiv.style.backgroundColor = "red";

		oDiv.style.left = vLeft + "px";
		oDiv.style.top = vTop + "px";
		oDiv.style.width = vWid + "px";
		oDiv.style.height = vHgt + "px";

		oDiv.style.visibility = "visible";

		vDoc.appendChild(oDiv);

	};

	/**
	 * Draw a diaganol line (calc line x,y pairs and draw multiple one-by-one sLines)
	 * @method dLine
	 * @return {void}
	 */
	this.dLine = function(x1, y1, x2, y2) {

		var dx = x2 - x1;
		var dy = y2 - y1;
		var x = x1;
		var y = y1;

		var n = Math.max(Math.abs(dx), Math.abs(dy));
		dx = dx / n;
		dy = dy / n;
		for (var i = 0; i <= n; i++) {
			vx = Math.round(x);
			vy = Math.round(y);
			this.sLine(vx, vy, vx, vy);
			x += dx;
			y += dy;
		}
		;

	};

	/**
	 * Draw dependency line between two points (task 1 end -> task 2 start)
	 * @method drawDependency
	 * @return {void}
	 */
	this.drawDependency = function(x1, y1, x2, y2) {
		if (vShowDep != 1)  return 0;
		if (x1 + 10 < x2) {
			this.sLine(x1, y1, x1 + 4, y1);
			this.sLine(x1 + 4, y1, x1 + 4, y2);
			this.sLine(x1 + 4, y2, x2, y2);
			this.dLine(x2, y2, x2 - 3, y2 - 3);
			this.dLine(x2, y2, x2 - 3, y2 + 3);
			this.dLine(x2 - 1, y2, x2 - 3, y2 - 2);
			this.dLine(x2 - 1, y2, x2 - 3, y2 + 2);
		}
		else {
			this.sLine(x1, y1, x1 + 4, y1);
			this.sLine(x1 + 4, y1, x1 + 4, y2 - 10);
			this.sLine(x1 + 4, y2 - 10, x2 - 8, y2 - 10);
			this.sLine(x2 - 8, y2 - 10, x2 - 8, y2);
			this.sLine(x2 - 8, y2, x2, y2);
			this.dLine(x2, y2, x2 - 3, y2 - 3);
			this.dLine(x2, y2, x2 - 3, y2 + 3);
			this.dLine(x2 - 1, y2, x2 - 3, y2 - 2);
			this.dLine(x2 - 1, y2, x2 - 3, y2 + 2);
		}
	};

	/**
	 * Draw all task dependencies
	 * @method DrawDependencies
	 * @return {void}
	 */
	this.DrawDependencies = function () {

		//First recalculate the x,y
		this.CalcTaskXY();

		this.clearDependencies();

		var vList = this.getList();
		for (var i = 0; i < vList.length; i++) {

			vDepend = vList[i].getDepend();
			if (vDepend) {

				var vDependStr = vDepend + '';
				var vDepList = vDependStr.split(',');
				var n = vDepList.length;

				for (var k = 0; k < n; k++) {
					var vTask = this.getArrayLocationByID(vDepList[k]);

					if (vList[vTask].getVisible() == 1)
						this.drawDependency(vList[vTask].getEndX(), vList[vTask].getEndY(), vList[i].getStartX() - 1, vList[i].getStartY())
				}
			}
		}
	};

	/**
	 * Find location of TaskItem based on the task ID
	 * @method getArrayLocationByID
	 * @return {void}
	 */
	this.getArrayLocationByID = function(pId) {
		var vList = this.getList();
		for (var i = 0; i < vList.length; i++) {
			if (vList[i].getID() == pId)
				return i;
		}
	};

	/**
	 * Get TaskItem based on the task ID
	 */
	this.getTaskItemByID = function(pId) {
		var vList = this.getList();
		for (var i = 0; i < vList.length; i++) {
			if (vList[i].getID() == pId)
				return vList[i];
		}
		return null;
	};

    var vDayWidth = 0;
	/**
	 * Draw gantt chart
	 * @method Draw
	 * @return {void}
	 */
	this.Draw = function() {
        var vTmpDate = new Date();
		var vMaxDate = new Date();
		var vMinDate = new Date();
		var vNxtDate = new Date();
		var vCurrDate = new Date();
		var vTaskLeft = 0;
		var vTaskRight = 0;
		var vNumCols = 0;
		var vID = 0;
		var vMainTable = "";
		var vLeftTable = "";
		var vRightTable = "";
		var vDateRowStr = "";
		var vItemRowStr = "";
		var vColWidth = 0;
		var vColUnit = 0;
		var vChartWidth = 0;
		var vNumDays = 0;
//		var vDayWidth = 0;
		var vStr = "";
		var vNameWidth = widthLeft;
		var vStatusWidth = 70;
//		var vLeftWidth = 15 + vNameWidth + 70 + 70 + 70;
		var vLeftWidth = 15 + vNameWidth + vStatusWidth*5;

		var vTaskStart;
		var vTaskEnd;
		var vTaskLen;
		var vTaskOfs;
		var vTaskColor;
		if (vTaskList.length > 0) {
            this.block();

			// Process all tasks preset parent date and completion %
			JSGantt.processRows(vTaskList, 0, -1, 1, 1);

			// get overall min/max dates plus padding
//			vMinDate = chartStart ? chartStart : JSGantt.getMinDate(vTaskList, vFormat);
//			vMaxDate = chartEnd ? chartEnd : JSGantt.getMaxDate(vTaskList, vFormat);

			vMinDate = JSGantt.getMinDate(vTaskList, vFormat);
			vMaxDate = JSGantt.getMaxDate(vTaskList, vFormat);
			if (chartStart && chartStart > vMinDate) vMinDate = chartStart;
			if (chartEnd && chartEnd < vMaxDate) vMaxDate = chartEnd;

//			alert(vMinDate+' - '+vMaxDate)

			// Calculate chart width variables.  vColWidth can be altered manually to change each column width
			// May be smart to make this a parameter of GanttChart or set it based on existing pWidth parameter
			if (vFormat == 'day') {			vColWidth = 18;vColUnit = 1;}
			else if (vFormat == 'week') {	vColWidth = 70;vColUnit = 7;}
			else if (vFormat == 'month') {	vColWidth = 90;vColUnit = 30;}
			else if (vFormat == 'quarter'){	vColWidth = 90;vColUnit = 90;}
			else if (vFormat == 'hour') {	vColWidth = 18;vColUnit = 1;}
			else if (vFormat == 'minute') {	vColWidth = 18;vColUnit = 1;}

			vNumDays = (Date.parse(vMaxDate) - Date.parse(vMinDate)) / DAY;
			vNumUnits = vNumDays / vColUnit;

			var NUM_UNITS_LIMIT = 500;
			if (vNumUnits > NUM_UNITS_LIMIT) {
				vMaxDate = new Date(vMinDate.getTime());
				vMaxDate.setDate(vMaxDate.getDate()+NUM_UNITS_LIMIT*vColUnit)

				vNumDays = (Date.parse(vMaxDate) - Date.parse(vMinDate)) / DAY;
				vNumUnits = vNumDays / vColUnit;
			}

			vChartWidth = vNumUnits * vColWidth + 1;
//			vDayWidth = (vColWidth / vColUnit) + Math.round(1 / vColUnit);
			vDayWidth = (vColWidth / vColUnit);


			//			if (vShowRes != 1) vNameWidth += vStatusWidth;
			//			if (vShowDur != 1) vNameWidth += vStatusWidth;
			//			if (vShowComp != 1) vNameWidth += vStatusWidth;
			//			if (vShowStartDate != 1) vNameWidth += vStatusWidth;
			//			if (vShowEndDate != 1) vNameWidth += vStatusWidth;

			if (vShowRes != 1) {vLeftWidth -= vStatusWidth;}//vChartWidth += vStatusWidth; }
			if (vShowDur != 1) {vLeftWidth -= vStatusWidth;}//vChartWidth += vStatusWidth; }
			if (vShowComp != 1) {vLeftWidth -= vStatusWidth;}//vChartWidth += vStatusWidth; }
			if (vShowStartDate != 1) {vLeftWidth -= vStatusWidth;}//vChartWidth += vStatusWidth; }
			if (vShowEndDate != 1) {vLeftWidth -= vStatusWidth;}//vChartWidth += vStatusWidth; }
			vChartWidth += 0;

			var nameHeight = $.browser.safari ? 19 : 20;


// Drawing begins
			vMainTable = '<TABLE id=theTable cellSpacing=0 cellPadding=0 border=0><TBODY>';
			vMainTable += '<TR><TD vAlign=top bgColor=#ffffff>';

			DrawLeftPart();
			DrawRightPart(this);

			vDiv.innerHTML = vMainTable;

            vDiv.onselectstart = function () { return false; }; // ie
            vDiv.onmousedown = function () { return false; }; // mozilla

            //----------------------------------------------------------------------------------------------------------
            var divs = $('div.divtask');
            var tasks = $('.gtask', divs);
//          var taskstarts = $('.gtaskstart', divs);
//          var taskends = $('.gtaskend', divs);
            var test1 = $('#rightside');
            var test2 = test1[0].parentNode;

            var dragopts = { /*containment: test2, */axis: 'x', scroll:false, grid: [vDayWidth, 10], start: onDragStart, drag: onDrag, stop: onDragStop};
            tasks.draggable(dragopts);
//            taskstarts.draggable(dragopts);
//            taskends.draggable(dragopts);

//            var rows = $('tr.yesdisplay');
            test1.selectable({ filter: '.yesdisplay' });
		}
		else vDiv.innerHTML = '';

		this.unblock();

		function DrawLeftTasks() {
			for (var i = 0; i < vTaskList.length; i++) {
                var task1 = vTaskList[i];
				if (isSkipStatus(task1.getCaption())) continue;
				if (task1.getStart() > vMaxDate) continue;
				if (task1.getEnd() < vMinDate) continue;

				if (task1.getStart() < vMinDate) continue;
				if (task1.getEnd() > vMaxDate) continue;

                vID = task1.getID();
                if (task1.getGroup()) {
                    var cookie = getCookie(task1.getName().hashCode());
                    if (cookie != null) task1.setOpen(parseInt(cookie));
					vBGColor = bggroupColor;
					vRowType = "group";
				} else {
					vBGColor = bgtaskColor;
					vRowType = "row";
				}
/*
                if (vTaskList[i].getParent()) {
                    vBGColor = "ffffff";
                } else {
                    vBGColor = "f3f3f3";
                }
*/
                if (task1.getParent())
                    task1.setVisible(vTaskList[task1.getParent()-1].getOpen());
                var hideTask = task1.getVisible() == 0 ? ' style="display:none" ' : '';
				var vTaskColor = JSGantt.getColorByPriority(task1.getPriority());
				vLeftTable += '<TR id=child_' + vID + ' bgcolor=' + vBGColor + ' onMouseover=g.mouseOver(this,' + vID + ',"left","' + vRowType + '") onMouseout=g.mouseOut(this,' + vID + ',"left","' + vRowType + '")'+hideTask+'>';
				vLeftTable += '  <TD class=gdatehead style="WIDTH: 15px; HEIGHT: '+nameHeight+'px; ">&nbsp;</TD>' +
                              '  <TD class=gname     style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; WIDTH: ' + vNameWidth + 'px; HEIGHT: '+nameHeight+'px;" nowrap>'+
/*
							  '  <TD class=gname     style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; WIDTH: ' + vNameWidth + 'px; HEIGHT: '+nameHeight+'px; background-color:#'+(task1.getLink()?vTaskColor:vBGColor)+';" nowrap>'+
*/
							  '  <NOBR style="background-color:#'+(task1.getLink()?vTaskColor:vBGColor)+';"><span style="color: #aaaaaa">';
				for (j = 1; j < task1.getLevel(); j++) {vLeftTable += '&nbsp;&nbsp;&nbsp;&nbsp;';}
				vLeftTable += '</span>';

				if (task1.getGroup()) {
                    vLeftTable += '<SPAN id="group_' + vID + '" style="color:#000000; cursor:pointer; font-weight:bold; FONT-SIZE: 12px;" onclick="JSGantt.folder(' + vID + ',' + vGanttVar + ');' + vGanttVar + '.DrawDependencies();">'+(task1.getOpen() == 1 ? '-' : '+')+'</span>&nbsp';
				} else {
					vLeftTable += '<span style="color: #000000; font-weight:bold; FONT-SIZE: 12px;">&nbsp;&nbsp;&nbsp;</span>';
				}

				if (task1.getParent()) vLeftTable += '<span style="color: #000000; font-weight:bold; FONT-SIZE: 12px;">&nbsp;&nbsp;&nbsp;&nbsp;</span>';

                if (task1.getLink()) {
                    var name = task1.getTrac()+': #'+task1.getTicket()+' '+task1.getName();
                    var tooltip = '('+task1.getStatus()+') #'+task1.getTicket()+' '+task1.getName();

/*
					vLeftTable += '<span style="cursor:pointer; background-color:#'+vTaskColor+';" title="'+tooltip+'" onclick=JSGantt.taskLink("' + task1.getLink() + '",1024,768);> ' + name + '</span></NOBR></TD>';
*/
					vLeftTable += '<span style="cursor:pointer;" title="'+tooltip+'" onclick="JSGantt.taskLink(\'' + task1.getLink() + '\',1024,768);"> ' + name + '</span></NOBR></TD>';
                } else
                    vLeftTable += '<span style="cursor:pointer; font-weight:bold;" onclick="JSGantt.folder(' + vID + ',' + vGanttVar + ');' + vGanttVar + '.DrawDependencies();"> ' + task1.getName() + '</span></NOBR></TD>';

				if (vShowRes == 1) vLeftTable += '  <TD class=gname style="WIDTH: 60px; HEIGHT: 20px; TEXT-ALIGN: center; BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;" align=center><NOBR>' + task1.getResource() + '</NOBR></TD>';
				if (vShowDur == 1) vLeftTable += '  <TD class=gname style="WIDTH: 60px; HEIGHT: 20px; TEXT-ALIGN: center; BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;" align=center><NOBR>' + task1.getDuration(vFormat) + '</NOBR></TD>';
				if (vShowComp == 1) vLeftTable += '  <TD class=gname style="WIDTH: 60px; HEIGHT: 20px; TEXT-ALIGN: center; BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;" align=center><NOBR>' + task1.getCompStr() + '</NOBR></TD>';
				if (vShowStartDate == 1) vLeftTable += '  <TD class=gname style="WIDTH: 60px; HEIGHT: 20px; TEXT-ALIGN: center; BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;" align=center><NOBR>' + JSGantt.formatDateStr(task1.getStart(), vDateDisplayFormat) + '</NOBR></TD>';
				if (vShowEndDate == 1) vLeftTable += '  <TD class=gname style="WIDTH: 60px; HEIGHT: 20px; TEXT-ALIGN: center; BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;" align=center><NOBR>' + JSGantt.formatDateStr(task1.getEnd(), vDateDisplayFormat) + '</NOBR></TD>';

				vLeftTable += '</TR>';

			}
		}
		function DrawLeftPart() {
// DRAW the Left-side of the chart (names, resources, comp%)
			vLeftTable =
					'<DIV class=scroll id=leftside style="width:' + vLeftWidth + 'px"><TABLE cellSpacing=0 cellPadding=0 border=0><TBODY>' +
							'<TR style="HEIGHT: 37px">' +
                            '  <TD style="WIDTH: 15px; HEIGHT: 37px"></TD>' +
							'  <TD style="WIDTH: ' + vNameWidth + 'px; HEIGHT: 37px"><NOBR></NOBR></TD>';

			if (vShowRes == 1) vLeftTable += '  <TD style="WIDTH: ' + vStatusWidth + 'px; HEIGHT: 17px"></TD>';
			if (vShowDur == 1) vLeftTable += '  <TD style="WIDTH: ' + vStatusWidth + 'px; HEIGHT: 17px"></TD>';
			if (vShowComp == 1) vLeftTable += '  <TD style="WIDTH: ' + vStatusWidth + 'px; HEIGHT: 17px"></TD>';
			if (vShowStartDate == 1) vLeftTable += '  <TD style="WIDTH: ' + vStatusWidth + 'px; HEIGHT: 17px"></TD>';
			if (vShowEndDate == 1) vLeftTable += '  <TD style="WIDTH: ' + vStatusWidth + 'px; HEIGHT: 17px"></TD>';

			/*vLeftTable +=
					'<TR style="HEIGHT: 20px">' +
							'  <TD style="BORDER-TOP: #efefef 1px solid; WIDTH: 15px; HEIGHT: 20px"></TD>' +
							'  <TD style="BORDER-TOP: #efefef 1px solid; WIDTH: ' + vNameWidth + 'px; HEIGHT: 20px"><NOBR></NOBR></TD>'; */

			if (vShowRes == 1) vLeftTable += '  <TD style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; WIDTH: 60px; HEIGHT: 20px" align=center nowrap>Resource</TD>';
			if (vShowDur == 1) vLeftTable += '  <TD style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; WIDTH: 60px; HEIGHT: 20px" align=center nowrap>Duration</TD>';
			if (vShowComp == 1) vLeftTable += '  <TD style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; WIDTH: 60px; HEIGHT: 20px" align=center nowrap>% Comp.</TD>';
			if (vShowStartDate == 1) vLeftTable += '  <TD style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; WIDTH: 60px; HEIGHT: 20px" align=center nowrap>Start Date</TD>';
			if (vShowEndDate == 1) vLeftTable += '  <TD style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; WIDTH: 60px; HEIGHT: 20px" align=center nowrap>End Date</TD>';

			vLeftTable += '</TR>';

//	DRAW right column
			DrawLeftTasks();

// DRAW the date format selector at bottom left.  Another potential GanttChart parameter to hide/show this selector
			vLeftTable += '</TD></TR>' +
					'<TR><TD border=1 colspan=5 align=left style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 11px; BORDER-LEFT: #efefef 1px solid; height=18px">'
				//					+'&nbsp;&nbsp;Powered by <a href=http://www.jsgantt.com>jsGantt</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Format:'
					;

			if (vFormatArr.join().indexOf("minute") != -1) {
				if (vFormat == 'minute') vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" VALUE="minute" checked>Minute';
				else				vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" onclick=JSGantt.changeFormat("minute",' + vGanttVar + '); VALUE="minute">Minute';
			}

			if (vFormatArr.join().indexOf("hour") != -1) {
				if (vFormat == 'hour') vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" VALUE="hour" checked>Hour';
				else				vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" onclick=JSGantt.changeFormat("hour",' + vGanttVar + '); VALUE="hour">Hour';
			}

			if (vFormatArr.join().indexOf("day") != -1) {
				if (vFormat == 'day') vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" VALUE="day" checked>Day';
				else				vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" onclick=JSGantt.changeFormat("day",' + vGanttVar + '); VALUE="day">Day';
			}

			if (vFormatArr.join().indexOf("week") != -1) {
				if (vFormat == 'week') vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" VALUE="week" checked>Week';
				else				vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" onclick=JSGantt.changeFormat("week",' + vGanttVar + ') VALUE="week">Week';
			}

			if (vFormatArr.join().indexOf("month") != -1) {
				if (vFormat == 'month') vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" VALUE="month" checked>Month';
				else				vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" onclick=JSGantt.changeFormat("month",' + vGanttVar + ') VALUE="month">Month';
			}

			if (vFormatArr.join().indexOf("quarter") != -1) {
				if (vFormat == 'quarter') vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" VALUE="quarter" checked>Quarter';
				else				vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" onclick=JSGantt.changeFormat("quarter",' + vGanttVar + ') VALUE="quarter">Quarter';
			}

			//            vLeftTable += '<INPUT TYPE=RADIO NAME="other" VALUE="other" style="display:none"> .';

			vLeftTable += '</TD></TR></TBODY></TABLE></TD>';

			vMainTable += vLeftTable;

		}
		function DrawRightPart(a) {
// Draw the Chart Rows
			vRightTable =
					'<TD vAlign=top bgColor=#ffffff>' +
							'<DIV class=scroll2 id=rightside style="width: '+widthRight+'px;">' +
							'<TABLE style="width: ' + vChartWidth + 'px;" cellSpacing=0 cellPadding=0 border=0>' +
							'<TBODY><TR style="HEIGHT: '+nameHeight+'px">';

			vTmpDate.setFullYear(vMinDate.getFullYear(), vMinDate.getMonth(), vMinDate.getDate());
			vTmpDate.setHours(0);
			vTmpDate.setMinutes(0);

vColWidth -= 2;
// Major Date Header
			while (Date.parse(vTmpDate) <= Date.parse(vMaxDate)) {
				vStr = vTmpDate.getFullYear() + '';
				vStr = vStr.substring(2, 4);


				if (vFormat == 'minute') {
					vRightTable += '<td class=gdatehead colspan=60>';
					vRightTable += JSGantt.formatDateStr(vTmpDate, vDateDisplayFormat) + ' ' + vTmpDate.getHours() + ':00 -' + vTmpDate.getHours() + ':59 </td>';
					vTmpDate.setHours(vTmpDate.getHours() + 1);
				}

				if (vFormat == 'hour') {
					vRightTable += '<td class=gdatehead colspan=24>';
					vRightTable += JSGantt.formatDateStr(vTmpDate, vDateDisplayFormat) + '</td>';
					vTmpDate.setDate(vTmpDate.getDate() + 1);
				}

				if (vFormat == 'day') {
					vStr = JSGantt.formatDateStr(vTmpDate, vDateDisplayFormat.substring(0, 5)) + ' - ';
					vTmpDate.setDate(vTmpDate.getDate() + 6);
					vStr += JSGantt.formatDateStr(vTmpDate, vDateDisplayFormat.substring(0, 5));
					vStr += ' `'+(vTmpDate.getFullYear() + '').substring(2, 4);
//                    vStr = '1 2 3 4 5 6 7 8 9 0'
					vRightTable += '<td class=gdatehead colspan=7>' + vStr + '</td>';
					vTmpDate.setDate(vTmpDate.getDate() + 1);
				}
				else if (vFormat == 'week') {
					vRightTable += '<td class=gdatehead width=' + vColWidth + 'px>`' + vStr + '</td>';
					vTmpDate.setDate(vTmpDate.getDate() + 7);
				}
				else if (vFormat == 'month') {
					vRightTable += '<td class=gdatehead width=' + vColWidth + 'px>`' + vStr + '</td>';
					vTmpDate.setDate(vTmpDate.getDate() + 1);
					while (vTmpDate.getDate() > 1) {
						vTmpDate.setDate(vTmpDate.getDate() + 1);
					}
				}
				else if (vFormat == 'quarter') {
					vRightTable += '<td class=gdatehead width=' + vColWidth + 'px>`' + vStr + '</td>';
					vTmpDate.setDate(vTmpDate.getDate() + 81);
					while (vTmpDate.getDate() > 1) {
						vTmpDate.setDate(vTmpDate.getDate() + 1);
					}
				}

			}

			vRightTable += '</TR><TR>';

// Minor Date header and Cell Rows
			vTmpDate.setFullYear(vMinDate.getFullYear(), vMinDate.getMonth(), vMinDate.getDate());
			vNxtDate.setFullYear(vMinDate.getFullYear(), vMinDate.getMonth(), vMinDate.getDate());
			vNumCols = 0;

            var vWeekdayColor;
			while (Date.parse(vTmpDate) <= Date.parse(vMaxDate)) {
				if (vFormat == 'minute') {
                    vWeekdayColor = vTmpDate.getMinutes() == 0 ? bgtodayColor : bgtaskColor;
                    vDateRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; HEIGHT: 19px; BORDER-LEFT: #efefef 1px solid;"  bgcolor=' + vWeekdayColor + ' align=center><div style="width: ' + vColWidth + 'px">' + vTmpDate.getMinutes() + '</div></td>';
                    vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; cursor: default;"  bgcolor=' + vWeekdayColor + ' align=center><div style="width: ' + vColWidth + 'px">&nbsp&nbsp</div></td>';
                    vTmpDate.setMinutes(vTmpDate.getMinutes() + 1);
                }

				else if (vFormat == 'hour') {
                    vWeekdayColor = vTmpDate.getHours() == 0 ? bgtodayColor : bgtaskColor;
                    vDateRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; HEIGHT: 19px; BORDER-LEFT: #efefef 1px solid;"  bgcolor=' + vWeekdayColor + ' align=center><div style="width: ' + vColWidth + 'px">' + vTmpDate.getHours() + '</div></td>';
                    vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; cursor: default;"  bgcolor=' + vWeekdayColor + ' align=center><div style="width: ' + vColWidth + 'px">&nbsp&nbsp</div></td>';
                    vTmpDate.setHours(vTmpDate.getHours() + 1);
                }

				else if (vFormat == 'day') {
                    var vWeekendColor;
					if (JSGantt.formatDateStr(vCurrDate, 'mm/dd/yyyy') == JSGantt.formatDateStr(vTmpDate, 'mm/dd/yyyy')) {
						vWeekdayColor = bgtodayColor;
						vWeekendColor = "#9999ff";
//						vWeekdayGColor = "bbbbff";
//						vWeekendGColor = "8888ff";
					} else {
//						vWeekdayColor = "ffffff";
//						vWeekendColor = "cfcfcf";
//						vWeekdayGColor = "f3f3f3";
//						vWeekendGColor = "c3c3c3";
                        vWeekdayColor = bgtaskColor;
                        vWeekendColor = bgweekendColor;
//                        vWeekdayGColor = "f3f3f3";
//                        vWeekendGColor = "e3e3e3";
					}

					var vDate = '<div style="width: ' + vColWidth + 'px">' + vTmpDate.getDate() + '</div></td>';
//					var vItem = '<div style="width: ' + vColWidth + 'px">&nbsp</div></td>';
					var vItem = '<div style="width: ' + vColWidth + 'px"/>&nbsp&nbsp</td>';
//					var vDate = vTmpDate.getDate() + '</td>';
//					var vItem = '</td>';
					if (vTmpDate.getDay() % 6 == 0) {
						vDateRowStr += '<td class="gheadwkend">'+vDate;
						vItemRowStr += '<td class="gheadwkend">'+vItem;
//						vDateRowStr += '<td class="gheadwkend" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; HEIGHT: 19px; BORDER-LEFT: #efefef 1px solid;" bgcolor=' + vWeekendColor + ' align=center><div style="width: ' + vColWidth + 'px">' + vTmpDate.getDate() + '</div></td>';
//						vItemRowStr += '<td class="gheadwkend" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; cursor: default;"  bgcolor=' + vWeekendColor + ' align=center><div style="width: ' + vColWidth + 'px">&nbsp</div></td>';
					}
					else {
						vDateRowStr += '<td class="ghead"  bgcolor=' + vWeekdayColor + '>'+vDate;
						if (JSGantt.formatDateStr(vCurrDate, 'mm/dd/yyyy') == JSGantt.formatDateStr(vTmpDate, 'mm/dd/yyyy'))
							vItemRowStr += '<td class="ghead"  bgcolor=' + vWeekdayColor + '>'+vItem;
						else
							vItemRowStr += '<td class="ghead">'+vItem;
//						vDateRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; HEIGHT: 19px; BORDER-LEFT: #efefef 1px solid;"  bgcolor=' + vWeekdayColor + ' align=center><div style="width: ' + vColWidth + 'px">' + vTmpDate.getDate() + '</div></td>';
//						if (JSGantt.formatDateStr(vCurrDate, 'mm/dd/yyyy') == JSGantt.formatDateStr(vTmpDate, 'mm/dd/yyyy'))
//							vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; cursor: default;"  bgcolor=' + vWeekdayColor + ' align=center><div style="width: ' + vColWidth + 'px">&nbsp&nbsp</div></td>';
//						else
//							vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; cursor: default;"  align=center><div style="width: ' + vColWidth + 'px">&nbsp&nbsp</div></td>';
					}

					vTmpDate.setDate(vTmpDate.getDate() + 1);

				}

				else if (vFormat == 'week') {

                    vNxtDate.setDate(vNxtDate.getDate() + 7);
                    vWeekdayColor = vCurrDate >= vTmpDate && vCurrDate < vNxtDate ? bgtodayColor : bgtaskColor;
                    if (vNxtDate <= vMaxDate) {
                        vDateRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; HEIGHT: 19px; BORDER-LEFT: #efefef 1px solid;" bgcolor=' + vWeekdayColor + ' align=center width:' + vColWidth + 'px><div style="width: ' + vColWidth + 'px">' + (vTmpDate.getMonth() + 1) + '/' + vTmpDate.getDate() + '</div></td>';
                        if (vCurrDate >= vTmpDate && vCurrDate < vNxtDate)
                            vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;" bgcolor=' + vWeekdayColor + ' align=center><div style="width: ' + vColWidth + 'px">&nbsp&nbsp</div></td>';
                        else
                            vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;" align=center><div style="width: ' + vColWidth + 'px">&nbsp&nbsp</div></td>';

                    } else {
                        vDateRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; HEIGHT: 19px; BORDER-LEFT: #efefef 1px solid; bgcolor=' + vWeekdayColor + ' BORDER-RIGHT: #efefef 1px solid;" align=center width:' + vColWidth + 'px><div style="width: ' + vColWidth + 'px">' + (vTmpDate.getMonth() + 1) + '/' + vTmpDate.getDate() + '</div></td>';
                        if (vCurrDate >= vTmpDate && vCurrDate < vNxtDate)
                            vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; BORDER-RIGHT: #efefef 1px solid;" bgcolor=' + vWeekdayColor + ' align=center><div style="width: ' + vColWidth + 'px">&nbsp&nbsp</div></td>';
                        else
                            vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; BORDER-RIGHT: #efefef 1px solid;" align=center><div style="width: ' + vColWidth + 'px">&nbsp&nbsp</div></td>';

                    }

                    vTmpDate.setDate(vTmpDate.getDate() + 7);

                }

				else if (vFormat == 'month') {

                    vNxtDate.setFullYear(vTmpDate.getFullYear(), vTmpDate.getMonth(), vMonthDaysArr[vTmpDate.getMonth()]);
                    vWeekdayColor = vCurrDate >= vTmpDate && vCurrDate < vNxtDate ? bgtodayColor : bgtaskColor;
                    if (vNxtDate <= vMaxDate) {
                        vDateRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; HEIGHT: 19px; BORDER-LEFT: #efefef 1px solid;" bgcolor=' + vWeekdayColor + ' align=center width:' + vColWidth + 'px><div style="width: ' + vColWidth + 'px">' + vMonthArr[vTmpDate.getMonth()].substr(0, 3) + '</div></td>';
                        if (vCurrDate >= vTmpDate && vCurrDate < vNxtDate)
                            vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;" bgcolor=' + vWeekdayColor + ' align=center><div style="width: ' + vColWidth + 'px">&nbsp&nbsp</div></td>';
                        else
                            vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;" align=center><div style="width: ' + vColWidth + 'px">&nbsp&nbsp</div></td>';
                    } else {
                        vDateRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; HEIGHT: 19px; BORDER-LEFT: #efefef 1px solid; BORDER-RIGHT: #efefef 1px solid;" bgcolor=' + vWeekdayColor + ' align=center width:' + vColWidth + 'px><div style="width: ' + vColWidth + 'px">' + vMonthArr[vTmpDate.getMonth()].substr(0, 3) + '</div></td>';
                        if (vCurrDate >= vTmpDate && vCurrDate < vNxtDate)
                            vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; BORDER-RIGHT: #efefef 1px solid;" bgcolor=' + vWeekdayColor + ' align=center><div style="width: ' + vColWidth + 'px">&nbsp&nbsp</div></td>';
                        else
                            vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; BORDER-RIGHT: #efefef 1px solid;" align=center><div style="width: ' + vColWidth + 'px">&nbsp&nbsp</div></td>';
                    }

                    vTmpDate.setDate(vTmpDate.getDate() + 1);

                    while (vTmpDate.getDate() > 1) {
                        vTmpDate.setDate(vTmpDate.getDate() + 1);
                    }

                }

				else if (vFormat == 'quarter') {

                    vNxtDate.setDate(vNxtDate.getDate() + 122);
                    if (vTmpDate.getMonth() == 0 || vTmpDate.getMonth() == 1 || vTmpDate.getMonth() == 2)
                        vNxtDate.setFullYear(vTmpDate.getFullYear(), 2, 31);
                    else if (vTmpDate.getMonth() == 3 || vTmpDate.getMonth() == 4 || vTmpDate.getMonth() == 5)
                        vNxtDate.setFullYear(vTmpDate.getFullYear(), 5, 30);
                    else if (vTmpDate.getMonth() == 6 || vTmpDate.getMonth() == 7 || vTmpDate.getMonth() == 8)
                        vNxtDate.setFullYear(vTmpDate.getFullYear(), 8, 30);
                    else if (vTmpDate.getMonth() == 9 || vTmpDate.getMonth() == 10 || vTmpDate.getMonth() == 11)
                        vNxtDate.setFullYear(vTmpDate.getFullYear(), 11, 31);
                    vWeekdayColor = vCurrDate >= vTmpDate && vCurrDate < vNxtDate ? bgtodayColor : bgtaskColor;
                    if (vNxtDate <= vMaxDate) {
                        vDateRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; HEIGHT: 19px; BORDER-LEFT: #efefef 1px solid;" bgcolor=' + vWeekdayColor + ' align=center width:' + vColWidth + 'px><div style="width: ' + vColWidth + 'px">Qtr. ' + vQuarterArr[vTmpDate.getMonth()] + '</div></td>';
                        if (vCurrDate >= vTmpDate && vCurrDate < vNxtDate)
                            vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;" bgcolor=' + vWeekdayColor + ' align=center><div style="width: ' + vColWidth + 'px">&nbsp&nbsp</div></td>';
                        else
                            vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;" align=center><div style="width: ' + vColWidth + 'px">&nbsp&nbsp</div></td>';
                    } else {
                        vDateRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; HEIGHT: 19px; BORDER-LEFT: #efefef 1px solid; BORDER-RIGHT: #efefef 1px solid;" bgcolor=' + vWeekdayColor + ' align=center width:' + vColWidth + 'px><div style="width: ' + vColWidth + 'px">Qtr. ' + vQuarterArr[vTmpDate.getMonth()] + '</div></td>';
                        if (vCurrDate >= vTmpDate && vCurrDate < vNxtDate)
                            vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; BORDER-RIGHT: #efefef 1px solid;" bgcolor=' + vWeekdayColor + ' align=center><div style="width: ' + vColWidth + 'px">&nbsp&nbsp</div></td>';
                        else
                            vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; BORDER-RIGHT: #efefef 1px solid;" align=center><div style="width: ' + vColWidth + 'px">&nbsp&nbsp</div></td>';
                    }

                    vTmpDate.setDate(vTmpDate.getDate() + 81);

                    while (vTmpDate.getDate() > 1) {
                        vTmpDate.setDate(vTmpDate.getDate() + 1);
                    }

                }
			}

			vRightTable += vDateRowStr + '</TR>';
			vRightTable += '</TBODY></TABLE>';

// Draw each row
			vTmpDate.setFullYear(vMinDate.getFullYear(), vMinDate.getMonth(), vMinDate.getDate());
			var tmp_tasks = '';
			for (i = 0; i < vTaskList.length; i++) {
				var tmp_task = a.drawTask(vTaskList[i], vChartWidth, vDayWidth, vItemRowStr, vColUnit, vMinDate, vMaxDate);
				tmp_tasks += tmp_task;
			}
			log('count: '+vTaskList.length+', size: '+(tmp_tasks.length/1000000).toFixed(2))

			vMainTable += vRightTable + tmp_tasks + '</DIV></TD></TR></TBODY></TABLE></BODY></HTML>';
		}
	}; //this.draw

    var dragging = false;
    var dragOffset;
    var dragSelected;
    var selection;
    var task;
    function onDragStart(event, ui) {
        dragging = true;
        dragOffset = 0;
        var dragid = parseInt(this.parentNode.id.substr(7));
        task = vTaskList[dragid - 1];
        selection = [];
        dragSelected = $('#'+this.parentNode.parentNode.id+' .yesdisplay').hasClass('ui-selected')
        if (dragSelected) $("#rightside .ui-selected").each(function(){selection.push(parseInt(this.id.substr(9)));});
        else selection.push(dragid);
    }
    function onDrag(event, ui) {
        var relOffset = (ui.position.left)/vDayWidth;
        var shift = (relOffset - task.getOffset()) * vDayWidth;
        if (dragSelected && shift != dragOffset) {
            for (var i in selection) {
                var elem = $('#bardiv_'+selection[i]+' .gtask');
                if (elem[0]) elem.css('left', elem[0].offsetLeft + shift - dragOffset);
            }
        }
        dragOffset = shift;
//            window.status = dragOffset+', '+dragSelected
    }
    function onDragStop(event, ui) {
        dragging = false;
        var relOffset = (ui.position.left)/vDayWidth;
        var offset = (relOffset-task.getOffset());

        var list = [];
        for (var i in selection) {
            task = vTaskList[selection[i] - 1];
            if (task.getGroup()) continue;
//            list.push([task.getTrac(), task.getTicket()]);
            list.push(task.getTrueTrac()+','+task.getTicket());
            task.setOffset(task.getOffset() + offset);
            task.getStart().setDate(task.getStart().getDate()+offset);
            task.getEnd().setDate(task.getEnd().getDate()+offset);
        }

        SendChanges(offset, list);

//        var start = new Date(task.getStart().getTime());
//        start.setDate(start.getDate()+offset);
//        var end = new Date(task.getEnd().getTime());
//        end.setDate(end.getDate()+offset);
//        task.setStart(start);
//        task.setEnd(end);
//        task.setOffset(relOffset);

    }
    this.block = function(){
//		$(vDiv).block();
		$.blockUI({ css: {
            border: 'none',
            padding: '15px',
            backgroundColor: '#000',
            '-webkit-border-radius': '10px',
            '-moz-border-radius': '10px',
            opacity: .5,
            color: '#fff'
        } });
	};
    this.unblock = function(){
//		$(vDiv).unblock();
		$.unblockUI();
	};

	this.drawTask = function(vTask, vChartWidth, vDayWidth, vItemRowStr, vColUnit, vMinDate, vMaxDate) {
		var vTaskStart = vTask.getStart();
		var vTaskEnd = vTask.getEnd();
		var vTaskColor = vTask.getColor();
		var vTaskID = vTask.getID();
		var vID = vTask.getID();
		var vTaskLoad = vTask.getLoad();

		var vRightTable = '';
		var vTaskLeft;
		var vTaskRight;
		var vDateRowStr;
		var vCaptionStr;
		var vNumCols = 0;
		var over;

		var vTaskDates = vTask.getDates();
		var vTaskSimple = vTaskDates == undefined || vTaskDates == null || vTaskDates.length == 0;
		var vTaskCount = vTaskSimple ? 1 : vTaskDates.length;
//		alert ('Task: '+vID+', '+vTaskSimple+', '+vTaskCount);

		if (isSkipStatus(vTask.getCaption())) return '';
		if (vTask.getStart() > vMaxDate) return '';
		if (vTask.getEnd() > vMaxDate) return '';

		if (vTask.getStart() < vMinDate) return '';
		if (vTask.getEnd() < vMinDate) return '';

        var hideTask = vTask.getVisible() == 0 ?' display:none;' : '';
        vRightTable += '<DIV id=childgrid_' + vTaskID + ' style="position:relative;'+hideTask+'">';
		for (var i = 0; i < vTaskCount; i++) {
			if (!vTaskSimple) {
				vTaskStart = JSGantt.parseDateStr(vTaskDates[i].start, g.getDateInputFormat());
				vTaskEnd = JSGantt.parseDateStr(vTaskDates[i].end, g.getDateInputFormat());
				vTaskLoad = JSGantt.getLoad(vTaskDates[i].load);
				vTaskColor = JSGantt.getColor(vTaskLoad);
				vID = vTask.getID()+'_'+i;
//				alert ('ComplexTask: '+vID+', '+vTaskStart+', '+vTaskEnd+', '+vTaskColor);
			}

            if (i == 0) {
                vRightTable += '<DIV><TABLE style="position:relative; top:0px; width: ' + vChartWidth + 'px;" cellSpacing=0 cellPadding=0 border=0>';
                var color = bgtaskColor;
                var type = 'row';
                if (vTask.getMile()) { type = 'mile'; }
                else if (vTask.getGroup()) { color = bggroupColor; type = 'group'; }
                over = ' onMouseover=g.mouseOver(this,' + vTaskID + ',"","'+type+'") onMouseout=g.mouseOut(this,' + vTaskID + ',"","'+type+'") ';
                vRightTable += '<TR id=childrow_' + vTaskID + ' class=yesdisplay style="HEIGHT: 20px"  bgColor='+color+over+'>' + vItemRowStr + '</TR></TABLE></DIV>';
            }

            if (!vTaskStart || !vTaskEnd) continue;
			if (vTaskStart > vMaxDate) continue;
			if (vTaskEnd < vMinDate) continue;

			if (vTaskStart < vMinDate) continue;
			if (vTaskEnd > vMaxDate) continue;

			var vTaskLen = vTaskEnd - vTaskStart;
			var vTaskOfs = vTaskStart - vMinDate;

//			else alert ('SimpleTask: '+vID+', '+vTaskStart+', '+vTaskEnd+', '+vTaskColor);


			// vNumUnits = Math.ceil((vTaskLen) / DAY) + 1;
			vNumUnits = vTaskLen / DAY + 1;
			if (vFormat == 'hour') {
				vNumUnits = vTaskLen / HOUR + 1;
			}
			else if (vFormat == 'minute') {
				vNumUnits = vTaskLen / MINUTE + 1;
			}

			if (vTask.getMile()) {

/*
				if (i == 0) {
				vRightTable += '<DIV><TABLE style="position:relative; top:0px; width: ' + vChartWidth + 'px;" cellSpacing=0 cellPadding=0 border=0>' +
						'<TR id=childrow_' + vTaskID + ' class=yesdisplay style="HEIGHT: 20px" onMouseover=g.mouseOver(this,' + vTaskID + ',"right","mile") onMouseout=g.mouseOut(this,' + vTaskID + ',"right","mile")>' + vItemRowStr + '</TR></TABLE></DIV>';
				}
*/

				// Build date string for Title
				vDateRowStr = JSGantt.formatDateStr(vTaskStart, vDateDisplayFormat);

				vTaskLeft = vTaskOfs / DAY;
				vTaskRight = 1;

				vRightTable +=
						'<div id=bardiv_' + vID + ' style="position:absolute; top:0px; left:' + Math.ceil((vTaskLeft * (vDayWidth) + 1)) + 'px; height: 18px; width:160px; overflow:hidden;">' +
								'  <div id=taskbar_' + vID + ' title="' + vTask.getName() + ': ' + vDateRowStr + '" style="height: 16px; width:12px; overflow:hidden; cursor: pointer;" onclick=JSGantt.taskLink("' + vTask.getLink() + '",300,200);>';

				if (vTask.getCompVal() < 100) {
					vRightTable += '&loz;</div>';
				}
				else {
					vRightTable += '&diams;</div>';
				}

				if (g.getCaptionType()) {
					vCaptionStr = '';
					switch (g.getCaptionType()) {
						case 'Caption':	vCaptionStr = vTask.getCaption();  break;
						case 'Resource':   vCaptionStr = vTask.getResource();  break;
						case 'Duration':   vCaptionStr = vTask.getDuration(vFormat);  break;
						case 'Complete':   vCaptionStr = vTask.getCompStr();  break;
					}
					//vRightTable += '<div style="FONT-SIZE:12px; position:absolute; left: 6px; top:1px;">' + vCaptionStr + '</div>';
					vRightTable += '<div style="FONT-SIZE:12px; position:absolute; top:2px; width:120px; left:12px">' + vCaptionStr + '</div>';
				}


				vRightTable += '</div>';


			} else {

				if (vFormat == 'minute') {
					vTaskRight = vTaskLen / MINUTE + 1;// / vColUnit;
					vTaskLeft = Math.ceil(vTaskOfs / MINUTE);
				}
				else if (vFormat == 'hour') {
					vTaskRight = vTaskLen / HOUR + 1;// / vColUnit;
					vTaskLeft = vTaskOfs / HOUR;
				}
				else {
					vTaskRight = vTaskLen / DAY + 1;// / vColUnit;
					vTaskLeft = Math.ceil(vTaskOfs / DAY);
					if (vFormat == 'day') {
						var tTime = new Date();
						tTime.setTime(vTaskStart);
						if (tTime.getMinutes() > 29)
							vTaskLeft += .5;
					}
				}

//				if (vTaskCount > 1) alert (vID+', '+vDateRowStr+', '+vTaskRight+', '+vTaskLeft+', '+vTaskLen+', '+vTaskOfs)

				// Draw Group Bar  which has outer div with inner group div and several small divs to left and right to create angled-end indicators
/*
				if (i == 0) {
					vRightTable += '<DIV><TABLE style="position:relative; top:0px; width: ' + vChartWidth + 'px;" cellSpacing=0 cellPadding=0 border=0>';
					if (vTask.getGroup()) {
						over = ' bgColor=#f3f3f3 onMouseover=g.mouseOver(this,' + vTaskID + ',"right1","group") onMouseout=g.mouseOut(this,' + vTaskID + ',"right1","group") ';
					} else {
						over = ' bgColor=#ffffff onMouseover=g.mouseOver(this,' + vTaskID + ',"right1","row")   onMouseout=g.mouseOut(this,' + vTaskID + ',"right1","row") ';
					}
					vRightTable += '<TR id=childrow_' + vTaskID + ' class=yesdisplay style="HEIGHT: 20px" '+over+'>' + vItemRowStr + '</TR></TABLE></DIV>';
				}
*/

				// Build date string for Title
				vDateRowStr = JSGantt.formatDateStr(vTaskStart, vDateDisplayFormat) + ' - ' + JSGantt.formatDateStr(vTaskEnd, vDateDisplayFormat);
                var task_left = Math.ceil(vTaskLeft * (vDayWidth) + /*1*/0);
                var tast_width = Math.ceil((vTaskRight) * (vDayWidth) - 1);
                if (/*/false /*/vTask.getGroup()/**/) {
                    var tooltip = vTask.getName() + ': ' + vDateRowStr;
                    vRightTable +=
						'<div class=divgroup id=bardiv_' + vID + ' style="left:' + task_left + 'px; width:' + tast_width + 'px">' +
								'<div class=gtask id=taskbar_' + vID + ' title="' + tooltip + '" style="width:' + tast_width + 'px;" '+over/*+'cursor: pointer;'*/+'>' +
//                        '<div class=divgroup id=bardiv_' + vID + ' style="position:absolute; top:5px; left:' + task_left + 'px; height: 7px; width:' + tast_width + 'px">' +
//                                '<div class=gtask id=taskbar_' + vID + ' title="' + tooltip + '" style="background-color:#000000; height: 7px; width:' + tast_width + 'px;opacity:0.9;" '+over/*+'cursor: pointer;'*/+'>' +
//                            '<div style="Z-INDEX: -4; float:left; background-color:#666666; height:3px; overflow: hidden; margin-top:1px; margin-left:1px; margin-right:1px; filter: alpha(opacity=80); opacity:0.8; cursor: pointer; width:' + vTask.getCompStr() + ';" onclick=JSGantt.taskLink("' + vTask.getLink() + '",300,200);></div>' +
                            '';
//                        '</div>';
                        /*+
                        '<div style="Z-INDEX: -4; float:left; background-color:#000000; height:4px; overflow: hidden; width:1px;"></div>' +
                        '<div style="Z-INDEX: -4; float:right; background-color:#000000; height:4px; overflow: hidden; width:1px;"></div>' +
                        '<div style="Z-INDEX: -4; float:left; background-color:#000000; height:3px; overflow: hidden; width:1px;"></div>' +
                        '<div style="Z-INDEX: -4; float:right; background-color:#000000; height:3px; overflow: hidden; width:1px;"></div>' +
                        '<div style="Z-INDEX: -4; float:left; background-color:#000000; height:2px; overflow: hidden; width:1px;"></div>' +
                        '<div style="Z-INDEX: -4; float:right; background-color:#000000; height:2px; overflow: hidden; width:1px;"></div>' +
                        '<div style="Z-INDEX: -4; float:left; background-color:#000000; height:1px; overflow: hidden; width:1px;"></div>' +
                        '<div style="Z-INDEX: -4; float:right; background-color:#000000; height:1px; overflow: hidden; width:1px;"></div>';*/
                } else {
                    var tooltip = vDateRowStr + ': ('+vTask.getStatus()+') #'+vTask.getTicket()+' '+vTask.getName();
					// Draw Task Bar  which has outer DIV with enclosed colored bar div, and opaque completion div
					vRightTable +=
						'<div class=divtask id=bardiv_' + vID + ' style="left:' + task_left + 'px; width:' + tast_width + 'px">' +
							'<div class=gtask id=taskbar_' + vID + ' title="' + tooltip + '" style="background-color:#' + vTaskColor + '; width:' + tast_width + 'px;" '+over/* + ' onclick=JSGantt.taskLink("' + vTask.getLink() + '",300,200); '*/+'>' +
							'<div class=gcomplete  style="width:' + vTask.getCompStr() + ';">' + '</div>' +
							'<div class=gtaskstart></div>' +
							'<div class=gtaskend  ></div>' +
							'';
//                        '<div class=divtask id=bardiv_' + vID + ' style="position:absolute; top:4px; left:' + task_left + 'px; height:18px; width:' + tast_width + 'px">' +
//                            '<div class=gtask id=taskbar_' + vID + ' title="' + tooltip + '" style="background-color:#' + vTaskColor + '; height: 13px; width:' + tast_width + 'px; cursor:e-resize;opacity:0.9;" '+over/* + ' onclick=JSGantt.taskLink("' + vTask.getLink() + '",300,200); '*/+'>' +
//                            '<div class=gcomplete  style="Z-INDEX: -4; float:left;  background-color:black; height:5px;  overflow: auto; margin-top:4px; filter: alpha(opacity=40); opacity:0.4; width:' + vTask.getCompStr() + '; overflow:hidden">' + '</div>' +
//                            '<div class=gtaskstart style="Z-INDEX: -4; float:left;  background-color:black; height:13px; overflow: hidden; width:1px; opacity:0.4; cursor:e-resize;"></div>' +
//                            '<div class=gtaskend   style="Z-INDEX: -4; float:right; background-color:black; height:13px; overflow: hidden; width:1px; opacity:0.5; cursor:e-resize;"></div>' +
//	                        '';
//                        '</div>';
				}
//                vRightTable += '</div>';

				if (g.getCaptionType()) {
					vCaptionStr = '';
					switch (g.getCaptionType()) {
						case 'Caption':	vCaptionStr = vTask.getCaption();  break;
						case 'Resource':   vCaptionStr = vTask.getResource();  break;
						case 'Duration':   vCaptionStr = vTask.getDuration(vFormat);  break;
						case 'Complete':   vCaptionStr = vTask.getCompStr();  break;
					}
					//vRightTable += '<div style="FONT-SIZE:12px; position:absolute; left: 6px; top:-3px;">' + vCaptionStr + '</div>';
//					vRightTable += '<div class="taskcaption" style="FONT-SIZE:12px; position:absolute; top:-3px; width:120px; left:' + (tast_width + 6) + 'px">' + vCaptionStr + '</div>';
                    vRightTable += '<div class="taskcaption" style="FONT-SIZE:12px; float:left; overflow: visible; width:120px; margin-top:-15px; margin-left:' + (tast_width + 6) + 'px">' + vCaptionStr + '</div></div>';
//                    vRightTable += '<div style="Z-INDEX: -4; float:right; overflow: visible; FONT-SIZE:12px; top:-20px;">' + vCaptionStr + '</div>';
				}

                vRightTable += '</div>';
			}

		}
		vRightTable += '</DIV>';

		return(vRightTable);
	};

	/**
	 * Mouseover behaviour for gantt row
	 * @method mouseOver
	 * @return {void}
	 */
	this.mouseOver = function(pObj, pID, pPos, pType) {
//		alert(pObj.id)
//		if (pPos == 'right')  vID = 'child_' + pID;
//		else vID = 'childrow_' + pID;

//        pobj.bgcolor = bgovercolor;
//        vrowobj = jsgantt.findobj('child_' + pid);
//        if (vrowobj) vrowobj.bgcolor = bgovercolor;
//        vrowobj = jsgantt.findobj('childrow_' + pid);
//        if (vrowobj) vrowobj.bgcolor = bgovercolor;

        if (dragging) return;
//        pObj.bgColor = JSGantt.findObj('child_' + pID).bgColor = JSGantt.findObj('childrow_' + pID).bgColor = bgoverColor;
//        JSGantt.findObj('child_' + pID).bgColor = JSGantt.findObj('childrow_' + pID).bgColor = bgoverColor;
        $('#child_' + pID).addClass('over');
        $('#childrow_' + pID).addClass('over');
	};

	/**
	 * Mouseout behaviour for gantt row
	 * @method mouseOut
	 * @return {void}
	 */
	this.mouseOut = function(pObj, pID, pPos, pType) {
//		alert(pObj.id)
//		if (pPos == 'right')  vID = 'child_' + pID;
//		else vID = 'childrow_' + pID;

//		pObj.bgColor = bgtaskColor;
//		vRowObj = JSGantt.findObj(vID);
//        vRowObj = JSGantt.findObj('child_' + pID);
//        vRowObj1 = JSGantt.findObj('childrow_' + pID);
//		if (vRowObj) {
//            pObj.bgColor = vRowObj.bgColor = vRowObj1.bgColor = (pType == "group") ? bggroupColor : bgtaskColor;
//		}

//        pObj.bgColor = JSGantt.findObj('child_' + pID).bgColor = JSGantt.findObj('childrow_' + pID).bgColor = (pType == "group") ? bggroupColor : bgtaskColor;
//        JSGantt.findObj('child_' + pID).bgColor = JSGantt.findObj('childrow_' + pID).bgColor = (pType == "group") ? bggroupColor : bgtaskColor;
        $('#child_' + pID).removeClass('over');
        $('#childrow_' + pID).removeClass('over');
	};

	this.addTask = function (task, parent) {
		if (task == undefined) return;
		//var isGroup = task.subtask != undefined && task.subtask.length > 0;
		// Parameters             	 (pName,     pStart,     pEnd,     pLoad,     pColor,                      pDates,	   pLink, 	    pMile, 	pRes,pComp, pGroup, 	pParent,pOpen, pDepend, pCaption)
		//var ti = new JSGantt.TaskItem(task.name, task.start, task.end, task.load, JSGantt.getColor(task.load), task.dates, task.link, 	0, 		'',  0, 	isGroup?1:0,parent, 0);
        var ti = new JSGantt.TaskItem(task, parent, 0);
		this.AddTaskItem(ti);
		for (var d in task.subtask) {
			this.addTask(task.subtask[d], ti.getID());
		}
	}

	this.createGantt = function (data, start, end) {
		this.setShowRes(0); // Show/Hide Responsible (0/1)
		this.setShowDur(0); // Show/Hide Duration (0/1)
		this.setShowComp(0); // Show/Hide % Complete(0/1)
		this.setCaptionType('Caption');  // Set to Show Caption (None,Caption,Resource,Duration,Complete)
		this.setShowStartDate(0); // Show/Hide Start Date(0/1)
		this.setShowEndDate(0); // Show/Hide End Date(0/1)
		this.setDateInputFormat('mm/dd/yyyy')  // Set format of input dates ('mm/dd/yyyy', 'dd/mm/yyyy', 'yyyy-mm-dd')
		this.setDateDisplayFormat('dd-mm-yyyy') // Set format to display dates ('mm/dd/yyyy', 'dd/mm/yyyy', 'yyyy-mm-dd')
		this.setFormatArr("day","week","month") // Set format options (up to 4 : "minute","hour","day","week","month","quarter")
		this.setShowDep(0);
//		this.setFormat('day')
		if (start) chartStart = JSGantt.parseDateStr(start, this.getDateInputFormat());
		if (end) chartEnd = JSGantt.parseDateStr(end, this.getDateInputFormat());

		this.loadGantt(data, vFormat);
/*
		for (var d in data) {
			this.addTask(data[d], 0);
		}

		this.Draw();
*/
	}

	var skipMode = "1";
	var currentData;
    this.loadGantt = function (data, pFormat) {
	    if (pFormat) vFormat = pFormat;
	    currentData = data;
        vTaskList = [];
        TaskPid = 1;
        for (var d in data) {
	        if ((skipMode == "1" && !data[d].dates) || (skipMode == "2" && data[d].dates)) continue;
            this.addTask(data[d], 0);
        }
	    try {
	        this.Draw();
	    }
	    catch (e) {
//		    ABDebug.console.show();
//		    log(e);
		    g.unblock();
	    }
    };

	this.ajaxGantt = function (data_type) {
		g.block();
		$.ajax({url:'http://td/supervisor/ticket/data', data:{'data_type': data_type}, dataType:'text', success:function(data) {
				try {
					var str = data.replace(/\r\n|\n/g, '<br/>');
					var d = eval('tmp = ' + str);
					g.setDatatype(data_type);
					g.createGantt(d);
				}
				catch (e) {
					ABDebug.console.show();
					log(e);
				}
				g.unblock();
			}});
	};

	$(pDiv).before('<div id="ganttFilter">'+JSGantt.getStatusFilter()+'</div>');
/*
	$("#statusFilterApply").click(function() {
		g.block();
		saveFilter();
		setTimeout("g.Draw();",10);
	});
*/
	$("#ganttFilter input.filter").change(function() {
		g.block();
		saveFilter();
		setTimeout("g.Draw();",10);
	});
	$("#statusFilterCollapse").click(function() {JSGantt.collapse(g);});
	$("#statusFilterExpand").click(function() {JSGantt.expand(g);});
	$("#statusFilterMode").change(function(){skipMode=this.value; g.loadGantt(currentData);});
	$(pDiv).after('<br/><div align="center"><span id="Undo" style="padding:0.5em; cursor:pointer; display:none;">Отменить изменение</span></div>');
	$('#Undo').button().click(function() {
	    if (lastChange) SendChanges(-lastChange.offset, lastChange.tasks);
	});
}; //GanttChart


/**
 *
 @class GanttChart
 */

JSGantt.getLoad = function (load) {
	return (load == undefined || load == null) ? 100 : load;
};
JSGantt.getColor = function (load) {
	load = JSGantt.getLoad(load);
//		if (load < 10)	return 'ccffcc'; else
    if (load <= 25) return 'c0c0FF'; else //new
    if (load <= 50) return 'bbddff'; else
    if (load <= 75) return '008000'; else //fixed
    if (load < 100) return '3355ff'; else
    if (load == 100)return 'c0c0c0'; else //global
    if (load < 150) return 'ff0000'; else
    if (load < 200)	return 'ffff00'; else //readyfortest
    if (load < 300)	return 'ff0080'; else //rejected
    return '800000'; //closed
};
JSGantt.getColorByStatus = function (status) {
    switch (status) {
        case 'new':             return '8080FF';
        case 'WorkerAppointed': return 'c0c0FF';
        case 'reopened':        return 'ff8080';
        case 'inwork':          return '80e0FF';
        case 'fixed':           return 'c0FFc0';
        case 'readyfortest':    return 'ffff80';
		case 'TesterAppointed': return 'ffff00';
        case 'intest':          return 'FFC040';
        case 'accepted':        return 'c0c0c0';
        case 'closed':          return 'd0d0d0';
        case 'rejected':        return 'ffc0c0';
        default:                return '000000';
    }
};
JSGantt.getColorByPriority = function (pri) {
    switch (pri) {
/*
        case 'blocker':         return 'FFEEDD';
        case 'critical':		return 'FFFFDD';
        case 'minor':           return 'E7FFFF';
        case 'trivial':    		return 'E7EEFF';
*/
		case 'blocker':         return 'FFDDCC';
		case 'critical':		return 'FFFFBB';
		case 'minor':           return 'DDFFFF';
		case 'trivial':    		return 'DDE7FF';
		case 'major':           return 'ffffff';
        default:                return 'ffffff';
    }
};
JSGantt.getStatusFilter = function () {
	var str = '';
	for (var i in STATUS) {
		var chk = getCookie("filter_"+i) == 'true';
		str += '<input class="filter" type="checkbox" '+(chk?'':'checked')+' id="'+i+'">&nbsp;<label for="'+i+'">'+STATUS[i].name+'</label>&nbsp;&nbsp;';
		for (var j in STATUS[i].stats) STATS[STATUS[i].stats[j]] = chk;
	}
	str += '<input type="button" value="-" id="statusFilterCollapse">';
	str += '<input type="button" value="+" id="statusFilterExpand">';
	str += '<select id="statusFilterMode"><option value="0">Все</option><option value="1" selected>С задачами</option><option value="2">Без задач</option></select>';
	return str;
};

function saveFilter() {
	for (var i in STATUS) {
		var chk = !$('#'+i)[0].checked;
		setCookie("filter_"+i, ""+chk, 365);
		for (var j in STATUS[i].stats) STATS[STATUS[i].stats[j]] = chk;
	}
	;
}

function loadFilter() {

}


function isSkipStatus(status) {
	if (status) {
		return STATS[status];
/*
		var check = $('#'+status);
		if (check && check[0])
		if (!check[0].checked)
			return true;
*/
	}
	return false;
}


/**
 * Checks whether browser is IE
 *
 * @method isIE
 */
JSGantt.isIE = function () {

	if (typeof document.all != 'undefined') {
		return true;
	}
	else {
		return false;
	}
};

/**
 * Recursively process task tree ... set min, max dates of parent tasks and identfy task level.
 *
 * @method processRows
 * @param pList {Array} - Array of TaskItem Objects
 * @param pID {Number} - task ID
 * @param pRow {Number} - Row in chart
 * @param pLevel {Number} - Current tree level
 * @param pOpen {Boolean}
 * @return void
 */
JSGantt.processRows = function(pList, pID, pRow, pLevel, pOpen) {

	var vMinDate = new Date();
	var vMaxDate = new Date();
	var vMinSet = 0;
	var vMaxSet = 0;
	var vList = pList;
	var vLevel = pLevel;
	var i = 0;
	var vNumKid = 0;
	var vCompSum = 0;
	var vVisible = pOpen;

	for (i = 0; i < pList.length; i++) {
		if (pList[i].getParent() == pID) {
			vVisible = pOpen;
			pList[i].setVisible(vVisible);
			if (vVisible == 1 && pList[i].getOpen() == 0) {
				vVisible = 0;
			}

			pList[i].setLevel(vLevel);
			vNumKid++;

//			if (pList[i].getGroup() == 1) {
//				JSGantt.processRows(vList, pList[i].getID(), i, vLevel + 1, vVisible);
//			}
			if (vMinSet == 0 || pList[i].getStart() < vMinDate) {
				vMinDate = pList[i].getStart();
				vMinSet = 1;
			}

			if (vMaxSet == 0 || pList[i].getEnd() > vMaxDate) {
				vMaxDate = pList[i].getEnd();
				vMaxSet = 1;
			}

			vCompSum += pList[i].getCompVal();

		}
	}

	if (pRow >= 0) {
		pList[pRow].setStart(vMinDate);
		pList[pRow].setEnd(vMaxDate);
		pList[pRow].setNumKid(vNumKid);
		pList[pRow].setCompVal(Math.ceil(vCompSum / vNumKid));
	}

};

/**
 * Determine the minimum date of all tasks and set lower bound based on format
 *
 * @method getMinDate
 * @param pList {Array} - Array of TaskItem Objects
 * @param pFormat {String} - current format (minute,hour,day...)
 * @return {Date}
 */
JSGantt.getMinDate = function getMinDate(pList, pFormat) {
    var vDate;
//	alert('getMinDate1: '+vDate);

    // Parse all Task End dates to find min
    for (i = 0; i < pList.length; i++) {
        var start2 = pList[i].getStart();
        if (!start2) continue;
        if (!vDate) {
            vDate = new Date();
            vDate.setFullYear(start2.getFullYear(), start2.getMonth(), start2.getDate());
        }
        if (Date.parse(start2) < Date.parse(vDate))
            vDate.setFullYear(start2.getFullYear(), start2.getMonth(), start2.getDate());
    }
//	alert('getMinDate2: '+vDate);
	if (!vDate) vDate = new Date();

    if (pFormat == 'minute') {
        vDate.setHours(0);
        vDate.setMinutes(0);
    }
    else if (pFormat == 'hour') {
        vDate.setHours(0);
        vDate.setMinutes(0);
    }
    // Adjust min date to specific format boundaries (first of week or first of month)
    else if (pFormat == 'day') {
        vDate.setDate(vDate.getDate() - 1);
        while (vDate.getDay() % 7 > 0) {
            vDate.setDate(vDate.getDate() - 1);
        }

    }

    else if (pFormat == 'week') {
        vDate.setDate(vDate.getDate() - 7);
        while (vDate.getDay() % 7 > 0) {
            vDate.setDate(vDate.getDate() - 1);
        }

    }

    else if (pFormat == 'month') {
        while (vDate.getDate() > 1) {
            vDate.setDate(vDate.getDate() - 1);
        }
    }

    else if (pFormat == 'quarter') {
        if (vDate.getMonth() == 0 || vDate.getMonth() == 1 || vDate.getMonth() == 2) {
            vDate.setFullYear(vDate.getFullYear(), 0, 1);
        }
        else if (vDate.getMonth() == 3 || vDate.getMonth() == 4 || vDate.getMonth() == 5) {
            vDate.setFullYear(vDate.getFullYear(), 3, 1);
        }
        else if (vDate.getMonth() == 6 || vDate.getMonth() == 7 || vDate.getMonth() == 8) {
            vDate.setFullYear(vDate.getFullYear(), 6, 1);
        }
        else if (vDate.getMonth() == 9 || vDate.getMonth() == 10 || vDate.getMonth() == 11) {
            vDate.setFullYear(vDate.getFullYear(), 9, 1);
        }

    }


    return(vDate);

};


/**
 * Used to determine the minimum date of all tasks and set lower bound based on format
 *
 * @method getMaxDate
 * @param pList {Array} - Array of TaskItem Objects
 * @param pFormat {String} - current format (minute,hour,day...)
 * @return {Date}
 */
JSGantt.getMaxDate = function (pList, pFormat) {
/*
	var vDate = new Date();

    var end = pList[0].getEnd();
    if (!end) return undefined;
    vDate.setFullYear(end.getFullYear(), end.getMonth(), end.getDate());
*/
//	alert('getMaxDate1: '+vDate);


	// Parse all Task End dates to find max
    var vDate;
	for (i = 0; i < pList.length; i++) {
        var end2 = pList[i].getEnd();
        if (!end2) continue;
        if (!vDate) {
            vDate = new Date();
            vDate.setFullYear(end2.getFullYear(), end2.getMonth(), end2.getDate());
        }
        if (Date.parse(end2) > Date.parse(vDate)) {
            vDate.setFullYear(end2.getFullYear(), end2.getMonth(), end2.getDate());
			//vDate.setFullYear(pList[0].getEnd().getFullYear(), pList[0].getEnd().getMonth(), pList[0].getEnd().getDate());
//			vDate.setTime(Date.parse(pList[i].getEnd()));
		}
	}
//	alert('getMaxDate2: '+vDate);
	if (!vDate) vDate = new Date();

	if (pFormat == 'minute') {
		vDate.setHours(vDate.getHours() + 1);
		vDate.setMinutes(59);
	}

	if (pFormat == 'hour') {
		vDate.setHours(vDate.getHours() + 2);
	}

	// Adjust max date to specific format boundaries (end of week or end of month)
	if (pFormat == 'day') {
		vDate.setDate(vDate.getDate() + 1);
		while (vDate.getDay() % 6 > 0) {vDate.setDate(vDate.getDate() + 1);}
	}

	if (pFormat == 'week') {
		//For weeks, what is the last logical boundary?
		vDate.setDate(vDate.getDate() + 11);
		while (vDate.getDay() % 6 > 0) {vDate.setDate(vDate.getDate() + 1);}
	}

	// Set to last day of current Month
	if (pFormat == 'month') {
		while (vDate.getDay() > 1) {vDate.setDate(vDate.getDate() + 1);}
		vDate.setDate(vDate.getDate() - 1);
	}

	// Set to last day of current Quarter
	if (pFormat == 'quarter') {
		if (vDate.getMonth() < 3)       vDate.setFullYear(vDate.getFullYear(), 2, 31);
		else if (vDate.getMonth() < 6)  vDate.setFullYear(vDate.getFullYear(), 5, 30);
		else if (vDate.getMonth() < 9)  vDate.setFullYear(vDate.getFullYear(), 8, 30);
		else                            vDate.setFullYear(vDate.getFullYear(), 11, 31);
	}

	return(vDate);

};


/**
 * Returns an object from the current DOM
 *
 * @method findObj
 * @param theObj {String} - Object name
 * @param theDoc {Document} - current document (DOM)
 * @return {Object}
 */
JSGantt.findObj = function (theObj, theDoc) {

	var p, i, foundObj;

	if (!theDoc) {
		theDoc = document;
	}

	if ((p = theObj.indexOf("?")) > 0 && parent.frames.length) {

		theDoc = parent.frames[theObj.substring(p + 1)].document;

		theObj = theObj.substring(0, p);

	}

	if (!(foundObj = theDoc[theObj]) && theDoc.all) {
		foundObj = theDoc.all[theObj];
	}


	for (i = 0; !foundObj && i < theDoc.forms.length; i++) {
		foundObj = theDoc.forms[i][theObj];
	}


	for (i = 0; !foundObj && theDoc.layers && i < theDoc.layers.length; i++) {
		foundObj = JSGantt.findObj(theObj, theDoc.layers[i].document);
	}


	if (!foundObj && document.getElementById) {
		foundObj = document.getElementById(theObj);
	}


	return foundObj;

};


/**
 * Change display format of current gantt chart
 *
 * @method changeFormat
 * @param pFormat {String} - Current format (minute,hour,day...)
 * @param ganttObj {GanttChart} - The gantt object
 * @return {void}
 */
JSGantt.changeFormat = function(pFormat, ganttObj) {

	if (ganttObj) {
		ganttObj.setFormat(pFormat);
		ganttObj.DrawDependencies();
	}
	else {
		alert('Chart undefined');
	}
};

function setFolderChar(pID, pChar) {
	var obj = JSGantt.findObj('group_' + pID);
	if (!obj) return;
    if (JSGantt.isIE())
        obj.innerText = pChar;
    else
        obj.textContent = pChar;
}

function getFolderChar(pID) {
	var obj = JSGantt.findObj('group_' + pID);
	if (!obj) '?';
    if (JSGantt.isIE())
        return obj.innerText;
    else
        return obj.textContent;
}

JSGantt.collapse = function (ganttObj) {
	var vList = ganttObj.getList();
	for (var i = 0; i < vList.length; i++) {
		var pID = vList[i].getID();
		if (vList[i].getOpen() == 1) {
			vList[i].setOpen(0);
			JSGantt.hide(pID, ganttObj);
			setFolderChar(pID, '+');
		}
		clearCookie(vList[i].getName().hashCode());
//		setCookie(vList[i].getName(), vList[i].getOpen(), 1);
	}
};
JSGantt.expand = function (ganttObj) {
	var vList = ganttObj.getList();
	for (var i = 0; i < vList.length; i++) {
		var pID = vList[i].getID();
		if (vList[i].getOpen() != 1) {
			vList[i].setOpen(1);
			JSGantt.show(pID, 1, ganttObj);
			setFolderChar(pID, '-');
		}
		if (vList[i].getGroup()) {
			setCookie(vList[i].getName().hashCode(), vList[i].getOpen(), 1);
//			var str = pID+', '+vList[i].getGroup()+', '+vList[i].getOpen()+', '+vList[i].getName().hashCode()+': '+vList[i].getName();
//		alert(str)
		}
	}
};

/**
 * Open/Close and hide/show children of specified task
 *
 * @method folder
 * @param pID {Number} - Task ID
 * @param ganttObj {GanttChart} - The gantt object
 * @return {void}
 */
JSGantt.folder = function (pID, ganttObj) {
	var vList = ganttObj.getList();
	for (var i = 0; i < vList.length; i++) {
		if (vList[i].getID() == pID) {
			if (vList[i].getOpen() == 1) {
				vList[i].setOpen(0);
				JSGantt.hide(pID, ganttObj);
                setFolderChar(pID, '+');
			} else {
				vList[i].setOpen(1);
				JSGantt.show(pID, 1, ganttObj);
                setFolderChar(pID, '-');
			}
            setCookie(vList[i].getName().hashCode(), vList[i].getOpen(), 1);
		}
	}
};

/**
 * Hide children of a task
 *
 * @method hide
 * @param pID {Number} - Task ID
 * @param ganttObj {GanttChart} - The gantt object
 * @return {void}
 */
JSGantt.hide = function (pID, ganttObj) {
	var vList = ganttObj.getList();
	var vID = 0;

	for (var i = 0; i < vList.length; i++) {
		if (vList[i].getParent() == pID) {
			vID = vList[i].getID();
			var obj = JSGantt.findObj('child_' + vID);
			if (obj) obj.style.display = "none";
			obj = JSGantt.findObj('childgrid_' + vID);
			if (obj) obj.style.display = "none";
			vList[i].setVisible(0);
			if (vList[i].getGroup() == 1) {
				JSGantt.hide(vID, ganttObj);
			}
		}
	}
//    setCookie(vList[pID-1].getName(), 0, 1);
};

/**
 * Show children of a task
 *
 * @method show
 * @param pID {Number} - Task ID
 * @param ganttObj {GanttChart} - The gantt object
 * @return {void}
 */
JSGantt.show = function (pID, pTop, ganttObj) {
	var vList = ganttObj.getList();
	var vID = 0;

	for (var i = 0; i < vList.length; i++) {
		if (vList[i].getParent() == pID) {
			vID = vList[i].getID();
			if (pTop == 1) {
                if (getFolderChar(pID) == '+') {
					var obj = JSGantt.findObj('child_' + vID);
					if (obj) obj.style.display = "";
					obj = JSGantt.findObj('childgrid_' + vID);
					if (obj) obj.style.display = "";
                    vList[i].setVisible(1);
                }
			} else {
                if (getFolderChar(pID) == '-') {
					var obj = JSGantt.findObj('child_' + vID);
					if (obj) obj.style.display = "";
					obj = JSGantt.findObj('childgrid_' + vID);
					if (obj) obj.style.display = "";
                    vList[i].setVisible(1);
                }
			}

			if (vList[i].getGroup() == 1) {
				JSGantt.show(vID, 0, ganttObj);
			}
		}
	}
//    setCookie(vList[pID-1].getName(), 1, 1);
};
/**
 * Handles click events on task name, currently opens a new window
 *
 * @method taskLink
 * @param pRef {String} - URL for window
 * @param pWidth {Number} - Width of window
 * @param pHeight {Number} - Height of window
 * @return {void}
 */
JSGantt.taskLink = function(pRef, pWidth, pHeight) {
    //return; // TODO: disabling clicks
    var vWidth = pWidth ? pWidth : 400;
    var vHeight = pHeight ? pHeight : 400;

//	var OpenWindow = window.open(pRef, "newwin", "height=" + vHeight + ",width=" + vWidth);
//    var OpenWindow = window.open(pRef, "newwin");
    var OpenWindow = window.open(pRef, "_blank");

};

/**
 * Parse dates based on gantt date format setting as defined in JSGantt.GanttChart.setDateInputFormat()
 *
 * @method parseDateStr
 * @param pDateStr {String} - A string that contains the date (i.e. "01/01/09")
 * @param pFormatStr {String} - The date format (mm/dd/yyyy,dd/mm/yyyy,yyyy-mm-dd)
 * @return {Date}
 */
JSGantt.parseDateStr = function(pDateStr, pFormatStr) {
	var vDate = new Date();

	if (pDateStr == undefined || pDateStr == null || pDateStr.length == 0) return undefined; //return(vDate);

	vDate.setTime(Date.parse(pDateStr));

    var vDateParts;
	switch (pFormatStr) {
        case 'mm/dd/yyyy':
            vDateParts = pDateStr.split('/');
            vDate.setFullYear(parseInt(vDateParts[2], 10), parseInt(vDateParts[0], 10) - 1, parseInt(vDateParts[1], 10));
            break;
		case 'dd/mm/yyyy':
			vDateParts = pDateStr.split('/');
			vDate.setFullYear(parseInt(vDateParts[2], 10), parseInt(vDateParts[1], 10) - 1, parseInt(vDateParts[0], 10));
			break;
		case 'yyyy-mm-dd':
			vDateParts = pDateStr.split('-');
			vDate.setFullYear(parseInt(vDateParts[0], 10), parseInt(vDateParts[1], 10) - 1, parseInt(vDateParts[1], 10));
			break;
	}

	return(vDate);

};

/**
 * Display a formatted date based on gantt date format setting as defined in JSGantt.GanttChart.setDateDisplayFormat()
 *
 * @method formatDateStr
 * @param pDate {Date} - A javascript date object
 * @param pFormatStr {String} - The date format (mm/dd/yyyy,dd/mm/yyyy,yyyy-mm-dd...)
 * @return {String}
 */
JSGantt.formatDateStr = function(pDate, pFormatStr) {
	vYear4Str = pDate.getFullYear() + '';
	vYear2Str = vYear4Str.substring(2, 4);
	vMonthStr = (pDate.getMonth() + 1) + '';
	vDayStr = pDate.getDate() + '';

	var vDateStr = "";

	switch (pFormatStr) {
		case 'mm/dd/yyyy':
			return( vMonthStr + '/' + vDayStr + '/' + vYear4Str );
		case 'dd/mm/yyyy':
			return( vDayStr + '/' + vMonthStr + '/' + vYear4Str );
		case 'yyyy-mm-dd':
			return( vYear4Str + '-' + vMonthStr + '-' + vDayStr );
		case 'mm/dd/yy':
			return( vMonthStr + '/' + vDayStr + '/' + vYear2Str );
		case 'dd/mm/yy':
			return( vDayStr + '/' + vMonthStr + '/' + vYear2Str );
		case 'yy-mm-dd':
			return( vYear2Str + '-' + vMonthStr + '-' + vDayStr );
		case 'mm/dd':
			return( vMonthStr + '/' + vDayStr );
		case 'dd/mm':
			return( vDayStr + '/' + vMonthStr );
		case 'dd-mm-yyyy':
			return( vDayStr + '-' + vMonthStr + '-' + vYear4Str );
		case 'dd-mm-yy':
			return( vDayStr + '-' + vMonthStr + '-' + vYear2Str );
		case 'dd-mm':
			return( vDayStr + '-' + vMonthStr);
	}

};

//----------------------------------------------------------------------------------------------------------------------
function setCookie(name,value,days) {
    var expires = "";
//	if (!value)
//		days = -1;
	if (days) {
		var date = new Date();
		date.setTime(date.getTime()+(days*DAY));
		expires = "; expires="+date.toGMTString();
	}
	document.cookie = escape(name)+"="+value+expires;//+"; path=/";
}

function getCookie(name) {
	var nameEQ = escape(name) + "=";
	var ca = document.cookie.split(';');
	for(var i=0;i < ca.length;i++) {
		var c = ca[i];
		while (c.charAt(0)==' ') c = c.substring(1,c.length);
		if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
	}
	return null;
}

function clearCookie(name) {
	setCookie(name,"",-1);
}

function AjaxErrorMsg(XMLHttpRequest, result, ex) {
//  var err1 = XMLHttpRequest.responseText ? eval("(" + XMLHttpRequest.responseText + ")").message +' -> ' : '';
    var error = 'Result: '+result+', Status: '+XMLHttpRequest.status+' '+XMLHttpRequest.statusText;
    var response = XMLHttpRequest.responseText ? '\n'+XMLHttpRequest.responseText : '';
    error += response.substr(0, 1000);
    if (ex) {
        error += '\nException: '+ ex;
        if (ex.fileName) error += ' at '+ ex.fileName;
        if (ex.lineNumber) error += ':'+ ex.lineNumber;
        if (ex.stack) error += '\n\t'+ ex.stack;//.substr(0, Math.min(200, ex.stack.length));
    }
    return error;
}

var lastChange = null;
function SendChanges(offset, list) {
    g.block();
//        var str = offset+': '+'  '+task.getTrac()+' #'+task.getTicket();
//        window.status = str;//alert(str);
//        $.get('/supervisor/ticket/change_task_date', {'offset':offset, 'tasks':'list'})
    var change = {'offset':offset, 'tasks':list.toString()};
    $.ajax({url: '/supervisor/ticket/change_task_date',
        data: change,
        type: "GET",
        global: false,
        error: function() {},
        complete: function(XMLHttpRequest, result) {
//                alert('change_task_date -> '+AjaxErrorMsg(XMLHttpRequest, result));
            lastChange = change;
            $('#Undo').show();
	        g.ajaxGantt(g.getDatatype());
/*
            $.getJSON('/supervisor/ticket/data', {},function(data){

	            try {
		            var str = data.replace(/\r\n|\n/g,'<br/>');
		            var d = eval('tmp = '+str);
		            g.createGantt(d);
	            }
	            catch (e) {
		            ABDebug.console.show();
		            log(e);
	            }
	            g.unblock();

            });
*/
        }
    });
}

$(function(){
    $.blockUI.defaults.fadeIn = 0;
    $.blockUI.defaults.fadeOut = 0;
    $.blockUI.defaults.message = '<h2>Идет работа мозга...</h2>';
    $.ajaxSetup({
        "error":function(XMLHttpRequest, result, ex) {
            g.unblock();
            alert(AjaxErrorMsg(XMLHttpRequest, result, ex));
        }
    });
});